import { Injectable } from '@angular/core';
import { Payload } from './payload';
import { State } from './state';
import { Store } from './store';

class ActionHolder {
    private stores: Array<{ instance: any, methodName: string }>;

    constructor(private actionType: string) {
        this.stores = [];
    }

    public add(instance: Store<any>, methodName: string) {
        this.stores.map((item) => {
            if (item.instance === instance) {
                return;
            }
        });
        this.stores.push({ instance, methodName });
    }

    public remove(instance: Store<any>) {
        this.stores = this.stores.filter((item) => {
            return item.instance !== instance;
        });
    }

    public invoke(payload: Payload) {
        this.stores.map((item) =>
            item.instance[item.methodName].apply(item.instance, [payload.data])
        );
    }
}

@Injectable()
export class Dispatcher {
    private actionRepository: {
        [key: string]: ActionHolder
    } = {};

    constructor() {
        console.log('Dispatcher#constructor');
    }

    public dispatch(payload: Payload) {
        const actionHolder = this.actionRepository[payload.actionType];
        if (actionHolder == null) {
            return;
        }
        actionHolder.invoke(payload);
    }

    public register(actionType: string, target: any, methodName: string) {
        const actionHolder = this.actionRepository[actionType] || new ActionHolder(actionType);
        actionHolder.add(target, methodName);
        this.actionRepository[actionType] = actionHolder;
    }

    public unregister(actionType: string, target: any) {
        const actionHolder = this.actionRepository[actionType];
        if (actionHolder == null) {
            return;
        }
        actionHolder.remove(target);
    }
}
